home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / inctrl.zip / INCTRS.ZIP / INCTRL.PAS < prev    next >
Pascal/Delphi Source File  |  1992-04-01  |  38KB  |  1,139 lines

  1. {$R-,S-,L-,D-}
  2. PROGRAM InCtrl;
  3. USES WinTypes, WinProcs, WObjects, Strings, WinDOS, StdDlgs, WinCrt,
  4.   FileSrch, FileReco;
  5. {$R InCtrl}
  6. {$D Copyright (c) 1992 by Neil J. Rubenking}
  7. {$I INCTRL.INC}
  8. CONST
  9.   AppName  : PChar = 'InCtrl';
  10.   CWinFile : PChar = 'WIN.INI';
  11.   CWinCopy : PChar = 'WININI.$$$';
  12.   CSysFile : PChar = 'SYSTEM.INI';
  13.   CSysCopy : PChar = 'SYSINI.$$$';
  14.   CommDlg  : PChar = 'COMMDLG.DLL';
  15.   BLen = 144;
  16. CONST {CommDlg constants}
  17.   ofn_ReadOnly             = $00000001;
  18.   ofn_OverWritePrompt      = $00000002;
  19.   ofn_HideReadOnly         = $00000004;
  20.   ofn_NoChangeDir          = $00000008;
  21.   ofn_ShowHelp             = $00000010;
  22.   ofn_EnableHook           = $00000020;
  23.   ofn_EnableTemplate       = $00000040;
  24.   ofn_EnableTemplateHandle = $00000080;
  25.   ofn_NoValidate           = $00000100;
  26.   ofn_AllowMultiSelect     = $00000200;
  27.   ofn_ExtentionDifferent   = $00000400;
  28.   ofn_PathMustExist        = $00000800;
  29.   ofn_FileMustExist        = $00001000;
  30.   ofn_CreatePrompt         = $00002000;
  31.   ofn_ShareAware           = $00004000;
  32.   ofn_NoReadOnlyReturn     = $00008000;
  33. TYPE
  34.   FileNameBuffer = ARRAY[0..BLen] OF Char;
  35.  
  36.   POpenFilename = ^TOpenFilename;
  37.   TOpenFilename = RECORD
  38.     lStructSize        : LongInt;
  39.     hwndOwner          : HWnd;
  40.     hInstance          : THandle;
  41.     lpstrFilter        : PChar;
  42.     lpstrCustomFilter  : PChar;
  43.     nMaxCustFilter     : LongInt;
  44.     nFilterIndex       : LongInt;
  45.     lpstrFile          : PChar;
  46.     nMaxFile           : LongInt;
  47.     lpstrFileTitle     : PChar;
  48.     nMaxFileTitle      : LongInt;
  49.     lpstrInitialDir    : PChar;
  50.     lpstrTitle         : PChar;
  51.     Flags              : LongInt;
  52.     nFileOffset        : WORD;
  53.     nFileExtension     : WORD;
  54.     lpstrDefExt        : PChar;
  55.     lCustData          : LongInt;
  56.     lpfnHook           : FUNCTION (Wnd : HWnd; Msg, wParam : Word;
  57.                            lParam : LongInt): Bool;
  58.     lpTemplateName     : PChar;
  59.   END;
  60.  
  61.   TCommDlgFunc = FUNCTION (VAR OpenFile : TOpenFilename) : Bool;
  62.  
  63.   TMyApplication = OBJECT(TApplication)
  64.     PROCEDURE InitMainWindow; virtual;
  65.   END;
  66.  
  67.   PCanHideIcon = ^TCanHideIcon;
  68.   TCanHideIcon = OBJECT(TStatic)
  69.     Hidden : Boolean;
  70.     PROCEDURE wmPaint(VAR Msg : TMessage); Virtual wm_First +
  71.       wm_Paint;
  72.     PROCEDURE Paint(PDC: HDC; VAR PS : TPaintStruct); Virtual;
  73.     PROCEDURE Hide(DoIt : Boolean);
  74.   END;
  75.  
  76.   PInstallData = ^TInstallData;
  77.   TInstallData = RECORD
  78.     ReptFile           : Text;
  79.     DirList            : PStrCollection;
  80.     FileList           : PFileRecordList;
  81.     NumFiles, NumDirs,
  82.     DelFiles, DelDirs,
  83.     ChFiles,  ChDirs,
  84.     NumSects, NumKeys,
  85.     NumKeyCh           : Word;
  86.   END;
  87.  
  88.   PInCtrlDialog = ^TInCtrlDialog;
  89.   TInCtrlDialog = OBJECT(TDlgWindow)
  90.     IData                : TInstallData;
  91.     InstProg,  ReptName  : FileNameBuffer;
  92.     InstProgS, ReptNameS : PStatic;
  93.     InstProgI, ReptNameI : PCanHideIcon;
  94.     Drives               : ARRAY['A'..'Z'] OF Boolean;
  95.     LineBuff             : ARRAY[0..80] OF Char;
  96.     CommDlgHandle        : THandle;
  97.     GetOpenFileName,
  98.     GetSaveFileName      : TCommDlgFunc;
  99.     CONSTRUCTOR Init(AParent : PWindowsObject; AName : PChar);
  100.     PROCEDURE SetUpWindow; Virtual;
  101.     DESTRUCTOR Done; Virtual;
  102.     FUNCTION GetClassName : PChar; Virtual;
  103.     PROCEDURE GetWindowClass(var AWndClass : TWndClass); Virtual;
  104.     PROCEDURE idHelp(VAR Msg : TMessage); Virtual id_First + id_Help;
  105.     PROCEDURE idAbout(VAR Msg : TMessage); Virtual id_First +
  106.       id_About;
  107.     PROCEDURE idInstProgBtn(VAR Msg : TMessage); Virtual id_First +
  108.       id_InstProgBtn;
  109.     PROCEDURE idReptNameBtn(VAR Msg : TMessage); Virtual id_First +
  110.       id_ReptNameBtn;
  111.     PROCEDURE idPerform(VAR Msg : TMessage); Virtual id_First +
  112.       id_Perform;
  113.   END;
  114.  
  115.   FUNCTION ExistFile(Name : PChar) : Boolean;
  116.   VAR
  117.     F    : File;
  118.     Attr : Word;
  119.   BEGIN
  120.     Assign(F, Name);
  121.     GetFAttr(F, Attr);
  122.     ExistFile := DosError = 0;
  123.   END;
  124.  
  125. {--------------------------------------------------}
  126. { TCanHideIcon's methods                           }
  127. {--------------------------------------------------}
  128.   PROCEDURE TCanHideIcon.wmPaint(VAR Msg : TMessage);
  129.   BEGIN
  130.     IF Hidden THEN TWindow.wmPaint(Msg)
  131.     ELSE DefWndProc(Msg);
  132.   END;
  133.  
  134.   PROCEDURE TCanHideIcon.Paint(PDC : hDC; VAR PS : TPaintStruct);
  135.   BEGIN
  136.     FillRect(PDC, PS.rcPaint, GetStockObject(LtGray_Brush));
  137.   END;
  138.  
  139.   PROCEDURE TCanHideIcon.Hide(DoIt : Boolean);
  140.   BEGIN
  141.     Hidden := DoIt;
  142.     InvalidateRect(hWindow, NIL, TRUE);
  143.   END;
  144.  
  145. {--------------------------------------------------}
  146. { TInCtrlDialog's methods                          }
  147. {--------------------------------------------------}
  148.   CONSTRUCTOR TInCtrlDialog.Init(AParent : PWindowsObject;
  149.     AName : PChar);
  150.   VAR SysDir : FileNameBuffer;
  151.   BEGIN
  152.     TDlgWindow.Init(AParent, AName);
  153.     InstProg[0] := #0;
  154.     ReptName[0] := #0;
  155.     New(InstProgS, InitResource(@Self, id_InstProg, BLen));
  156.     New(ReptNameS, InitResource(@Self, id_ReptName, BLen));
  157.     New(InstProgI, InitResource(@Self, id_InstProgCk, 0));
  158.     New(ReptNameI, InitResource(@Self, id_ReptNameCk, 0));
  159.     InstProgI^.Hide(TRUE);
  160.     ReptNameI^.Hide(TRUE);
  161.     GetSystemDirectory(SysDir, BLen);
  162.     StrCat(SysDir, '\');
  163.     StrCat(SysDir, CommDlg);
  164.     IF NOT ExistFile(SysDir) THEN CommDlgHandle := 0
  165.     ELSE CommDlgHandle := LoadLibrary(CommDlg);
  166.     IF CommDlgHandle >= 32 THEN
  167.       BEGIN
  168.         TFarProc(@GetOpenFileName) := GetProcAddress(CommDlgHandle,
  169.           'GETOPENFILENAME');
  170.         TFarProc(@GetSaveFileName) := GetProcAddress(CommDlgHandle,
  171.           'GETSAVEFILENAME');
  172.         IF (TFarProc(@GetOpenFileName) = NIL) OR
  173.            (TFarProc(@GetSaveFileName) = NIL) THEN
  174.           BEGIN
  175.             FreeLibrary(CommDlgHandle);
  176.             CommDlgHandle := 0;
  177.           END;
  178.       END
  179.     ELSE CommDlgHandle := 0;
  180.   END;
  181.  
  182.   PROCEDURE TInCtrlDialog.SetUpWindow;
  183.   VAR
  184.     PL    : PListBox;
  185.     N, W  : Word;
  186.     Drive : ARRAY[0..6] OF Char;
  187.   BEGIN
  188.     TDialog.SetUpWindow;
  189.     New(PL, Init(@Self, 101, 0, 0, 0, 0));
  190.       {-Invisible list box takes advantage of the Windows lb_Dir-}
  191.       {-message to get a list of all drives on the system.      -}
  192.     PL^.Attr.Style := PL^.Attr.Style AND NOT ws_Visible;
  193.     PL := PListBox(Application^.MakeWindow(PL));
  194.     SendMessage(PL^.hWindow, lb_Dir, $4000 + $8000, 
  195.       LongInt(PChar('*.*')));
  196.     FillChar(Drives, SizeOf(Drives), FALSE);
  197.     FOR N := 0 TO Pred(PL^.GetCount) DO
  198.       BEGIN
  199.         PL^.GetString(Drive, N);
  200.           {-Drive now contains a string like "[-a-]" - next 2 lines-}
  201.           {-strip the punctuation and uppercase the drive letter.  -}
  202.         StrLCopy(drive, drive + 2, 1);
  203.         StrUpper(drive);
  204.         Drives[Drive[0]] :=
  205.           GetDriveType(Ord(Drive[0])-Ord('A')) = Drive_Fixed;
  206.         IF Drives[Drive[0]] THEN
  207.           BEGIN
  208.             W := GetPrivateProfileInt('Excluded drives', Drive, 0,
  209.               'INCTRL.INI');
  210.             IF W <> 0 THEN Drives[Drive[0]] := FALSE;
  211.           END;
  212.       END;
  213.     Dispose(PL, Done);
  214.   END;
  215.  
  216.   DESTRUCTOR TInCtrlDialog.Done;
  217.   BEGIN
  218.     IF CommDlgHandle <> 0 THEN FreeLibrary(CommDlgHandle);
  219.     TDialog.Done;
  220.   END;
  221.  
  222.   FUNCTION TInCtrlDialog.GetClassName;
  223.   BEGIN
  224.     GetClassName := AppName;
  225.   END;
  226.  
  227.   PROCEDURE TInCtrlDialog.GetWindowClass(VAR AWndClass : TWndClass);
  228.   BEGIN
  229.     TDlgWindow.GetWindowClass(AWndClass);
  230.     AWndClass.hIcon := LoadIcon(HInstance, AppName);
  231.   END;
  232.  
  233.   PROCEDURE TInCtrlDialog.idHelp(VAR Msg : TMessage);
  234.   BEGIN
  235.     Application^.ExecDialog(New(PDialog,Init(@Self, 'InCtrlHelp')));
  236.   END;
  237.  
  238.   PROCEDURE TInCtrlDialog.idAbout(VAR Msg : TMessage);
  239.   BEGIN
  240.     Application^.ExecDialog(New(PDialog,Init(@Self, 'InCtrlAbout')));
  241.   END;
  242.  
  243.   PROCEDURE TInCtrlDialog.idInstProgBtn(VAR Msg : TMessage);
  244.   CONST
  245.     filter : PChar = 'All Executable'#0'*.exe;*.com;*.bat'#0+
  246.                      'EXE'#0'*.exe'#0+
  247.                      'COM'#0'*.com'#0+
  248.                      'Batch'#0'*.bat'#0#0;
  249.   VAR
  250.     PFD              : PFileDialog;
  251.     TOF              : TOpenFilename;
  252.     ExistOk, Success : Boolean;
  253.   BEGIN
  254.     InstProgS^.GetText(InstProg, BLen);
  255.     IF CommDlgHandle = 0 THEN
  256.       BEGIN
  257.         IF InstProg[0] = #0 THEN StrCopy(InstProg, '*.EXE');
  258.         REPEAT
  259.           ExistOk := TRUE;
  260.           New(PFD, Init(@Self, PChar(sd_FileOpen), InstProg));
  261.           PFD^.Caption := 'Installation Program';
  262.           Success := Application^.ExecDialog(PFD) = IDOK;
  263.           IF Success THEN
  264.             BEGIN
  265.               IF NOT ExistFile(InstProg) THEN
  266.                  BEGIN
  267.                    ExistOk := FALSE;
  268.                    MessageBeep(mb_IconStop);
  269.                    MessageBox(hWindow, 'File does not '+
  270.                      'exist', InstProg, mb_Ok + mb_IconStop);
  271.                  END;
  272.             END;
  273.         UNTIL ExistOk;
  274.       END
  275.     ELSE
  276.       BEGIN
  277.         FillChar(TOF, SizeOf(TOF), 0);
  278.         WITH TOF DO
  279.           BEGIN
  280.             lStructSize   := SizeOf(TOF);
  281.             hwndOwner     := hWindow;
  282.             lpstrFilter   := filter;
  283.             nFilterIndex  := 1;
  284.             lpstrFile     := InstProg;
  285.             nMaxFile      := BLen;
  286.             lpstrTitle    := 'Installation Program';
  287.             lpstrDefExt   := 'EXE';
  288.             Flags         := ofn_FileMustExist OR ofn_HideReadOnly;
  289.           END;
  290.         Success := GetOpenFileName(TOF);
  291.       END;
  292.     IF Success THEN
  293.       BEGIN
  294.         StrUpper(InstProg);
  295.         InstProgS^.SetText(InstProg);
  296.         InstProgI^.Hide(FALSE);
  297.           {-If the report file name has also been chosen, now is-}
  298.           {-the time to enable the Perform button.              -}
  299.         IF ReptName[0] <> #0 THEN
  300.           EnableWindow(GetDlgItem(hWindow, id_Perform), TRUE);
  301.       END;
  302.   END;
  303.  
  304.   PROCEDURE TInCtrlDialog.idReptNameBtn(VAR Msg : TMessage);
  305.   CONST filter : PChar = 'InCtrl Report (*.RPT)'#0'*.RPT'#0#0;
  306.   VAR
  307.     PFD              : PFileDialog;
  308.     TOF              : TOpenFilename;
  309.     ReptDir          : FileNameBuffer;
  310.     WriteOk, Success : Boolean;
  311.   BEGIN
  312.     ReptNameS^.GetText(ReptName, BLen);
  313.     GetPrivateProfileString('Directories', 'ReptDir', '',
  314.       ReptDir, BLen, 'INCTRL.INI');
  315.     IF ReptDir[0] <> #0 THEN
  316.       BEGIN
  317.         SetCurDir(ReptDir);
  318.         IF DosError <> 0 THEN
  319.           BEGIN
  320.             MessageBeep(mb_IconInformation);
  321.             MessageBox(hWindow, 'Invalid default report directory '+
  322.               'in INCTRL.INI'^M'Using Windows directory instead.',
  323.               ReptDir, mb_Ok + mb_IconInformation);
  324.             ReptDir[0] := #0;
  325.           END;
  326.       END;
  327.     IF ReptDir[0] = #0 THEN GetWindowsDirectory(ReptDir, BLen);
  328.     IF CommDlgHandle = 0 THEN
  329.       BEGIN
  330.         IF ReptName[0] = #0 THEN StrCopy(ReptName, '*.RPT');
  331.         SetCurDir(ReptDir);
  332.         REPEAT
  333.           WriteOk := TRUE;
  334.           New(PFD, Init(@Self, PChar(sd_FileSave), ReptName));
  335.           PFD^.Caption := 'Name for Output Report';
  336.           Success := Application^.ExecDialog(PFD) = IDOK;
  337.           IF Success THEN
  338.             BEGIN
  339.               IF ExistFile(ReptName) THEN
  340.                  BEGIN
  341.                    MessageBeep(mb_IconQuestion);
  342.                    WriteOk := MessageBox(hWindow, 'File already '+
  343.                      'exists.'^M'Replace existing file?', ReptName,
  344.                      mb_YesNo + mb_IconInformation +
  345.                      mb_DefButton2) = IDYES;
  346.                  END;
  347.             END;
  348.         UNTIL WriteOk;
  349.       END
  350.     ELSE
  351.       BEGIN
  352.         FillChar(TOF, SizeOf(TOF), 0);
  353.         WITH TOF DO
  354.           BEGIN
  355.             lStructSize     := SizeOf(TOF);
  356.             hwndOwner       := hWindow;
  357.             lpstrFilter     := filter;
  358.             nFilterIndex    := 1;
  359.             lpstrFile       := ReptName;
  360.             nMaxFile        := BLen;
  361.             lpstrInitialDir := ReptDir;
  362.             lpstrTitle      := 'Name for Output Report';
  363.             lpstrDefExt     := 'RPT';
  364.             Flags           := ofn_HideReadOnly OR ofn_PathMustExist
  365.                                OR ofn_OverwritePrompt;
  366.           END;
  367.         Success := GetSaveFileName(TOF);
  368.       END;
  369.     IF Success THEN
  370.       BEGIN
  371.         StrUpper(ReptName);
  372.         ReptNameS^.SetText(ReptName);
  373.         ReptNameI^.Hide(FALSE);
  374.           {-If the install program name has also been chosen, now-}
  375.           {-is the time to enable the Perform button.            -}
  376.         IF InstProg[0] <> #0 THEN
  377.           EnableWindow(GetDlgItem(hWindow, id_Perform), TRUE);
  378.       END;
  379.   END;
  380.  
  381.   VAR GlobalData : PInstallData;
  382.     {-File search routines cannot be methods and hence don't have-}
  383.     {-access to the data field IData.  This global variable is   -}
  384.     {-simply set to *POINT* to IData.                            -}
  385.  
  386.   FUNCTION ListDir(VAR S : TSearchRec; P : PChar) : Byte; FAR;
  387.     {-Passed to the FileSrch routines to get a list of directories.-}
  388.   VAR Fullpath : ARRAY[0..144] OF Char;
  389.   BEGIN
  390.     ListDir := 0;
  391.     IF S.Attr AND faDirectory = 0 THEN Exit;
  392.     IF S.Name[0] = '.' THEN Exit;
  393.     StrCopy(FullPath, P);
  394.     StrCat(FullPath, S.Name);
  395.     IF StrLen(FullPath) > 3 THEN StrCat(FullPath, '\');
  396.     GlobalData^.DirList^.Insert(StrNew(fullPath));
  397.   END;
  398.  
  399.   FUNCTION Snap(VAR S : TSearchRec; P : PChar) : Byte; FAR;
  400.     {-Passed to the routines in the FileSrch unit. Assumes that-}
  401.     {-DirList is initialized with a list of all directories.   -}
  402.   VAR Indx : Integer;
  403.   BEGIN
  404.     Snap := 0;
  405.       {-Ignore . and .. entries. -}
  406.     IF S.Name[0] = '.' THEN Exit;
  407.     Snap := 128;
  408.     IF LowMemory THEN Exit;
  409.     Snap := 129;
  410.     WITH GlobalData^ DO
  411.       BEGIN
  412.         IF FileList^.Count = 16380 THEN Exit;
  413.         Snap := 0;
  414.         DirList^.Search(P, Indx);
  415.         WITH S DO
  416.           FileList^.Insert(New(PFileRecord, Init(Name,
  417.             Attr AND faDirectory <> 0, Indx, Time, Size, DirList)));
  418.       END;
  419.   END;
  420.  
  421.   FUNCTION UnSnap(VAR S : TSearchRec; P : PChar) : Byte; FAR;
  422.     {-Passed to the routines in the FileSrch unit-}
  423.   VAR
  424.     Indx     : Integer;
  425.     PFR      : PFileRecord;
  426.     Found    : Boolean;
  427.   BEGIN
  428.     UnSnap := 128;
  429.     IF LowMemory THEN Exit;
  430.     UnSnap := 0;
  431.     IF S.Name[0] = '.' THEN Exit;
  432.     WITH GlobalData^ DO
  433.       BEGIN
  434.         IF NOT DirList^.Search(P, Indx) THEN Found := FALSE
  435.         ELSE
  436.           BEGIN
  437.             New(PFR, Init(S.Name, FALSE, Indx, 0, 0, DirList));
  438.             Found := FileList^.Search(PFR, Indx);
  439.             Dispose(PFR, Done);
  440.           END;
  441.         IF Found THEN
  442.           BEGIN
  443.               {-If the item is on the list of existing files, -}
  444.               {-see if it changed.  If not changed, ditch it! -}
  445.             PFR := FileList^.At(Indx);
  446.             IF (PFR^.GetTime <> S.Time) OR
  447.                (PFR^.GetSize <> S.Size) THEN
  448.               PFR^.SetChanged
  449.             ELSE FileList^.AtFree(Indx)
  450.           END
  451.         ELSE
  452.           BEGIN
  453.             IF S.Attr AND faDirectory <> 0 THEN
  454.               BEGIN
  455.                 Inc(NumDirs);
  456.                 Write(ReptFile, 'DIR : ');
  457.               END
  458.             ELSE
  459.               BEGIN
  460.                 Inc(NumFiles);
  461.                 Write(ReptFile, 'FILE: ');
  462.               END;
  463.             WriteLn(ReptFile, P, S.Name);
  464.           END;
  465.         END;
  466.   END;
  467.  
  468.   PROCEDURE TInCtrlDialog.idPerform(VAR Msg : TMessage);
  469.   CONST Mask : PChar = '?:\*.*';
  470.   VAR
  471.     PD                : PDialog;
  472.     WinFile, WinCopy,
  473.     SysFile, SysCopy  : PChar;
  474.     W, WinDirLen      : Word;
  475.  
  476.     PROCEDURE Gasp;
  477.     VAR Mpeek : TMsg;
  478.     BEGIN
  479.       WHILE PeekMessage(mPeek, 0, 0, 0, PM_Remove) DO
  480.         BEGIN
  481.           IF mPeek.Message = WM_QUIT THEN
  482.             BEGIN
  483.               Application^.Done;
  484.               Halt;
  485.             END;
  486.           TranslateMessage(mPeek);
  487.           DispatchMessage(mPeek);
  488.         END;
  489.     END;
  490.  
  491.     PROCEDURE WarnWait(Message : PChar);
  492.     BEGIN
  493.       PD := New(PDialog, Init(@Self, 'WaitWarn'));
  494.       PD := PDialog(Application^.MakeWindow(PD));
  495.       SetDlgItemText(pd^.hWindow, id_WaitReason, Message);
  496.       PD^.Show(sw_ShowNormal);
  497.         {-"Gasp" so Windows can process the messages that display-}
  498.         {-the dialog and its controls.                           -}
  499.       Gasp;
  500.     END;
  501.  
  502.     PROCEDURE EndWait;
  503.     BEGIN
  504.       IF PD <> NIL THEN Dispose(PD, Done);
  505.       PD := NIL;
  506.       Gasp;
  507.     END;
  508.  
  509.     PROCEDURE WriteHeader;
  510.     CONST Days : PChar = 'SunMonTueWedThuFriSat';
  511.     VAR
  512.       StartTime : RECORD
  513.         Month, Day, Year, Hour, Min, Sec, Hund, Dow : Word;
  514.       END;
  515.     BEGIN
  516.       WITH IData, StartTime DO
  517.         BEGIN
  518.           GetTime(Hour, Min, Sec, Hund);
  519.           GetDate(Year, Month, Day, Dow);
  520.           WriteLn(ReptFile, 'INSTALLATION REPORT - ', InstProg);
  521.           WriteLn(ReptFile);
  522.           WriteLn(ReptFile, 'Produced by INCTRL, Copyright (c) '+
  523.             '1992 by Neil J. Rubenking');
  524.           StrLCopy(LineBuff, Days+(Dow*3), 3);
  525.           Write(ReptFile, LineBuff);
  526.           wvsprintf(LineBuff, ' %u/%u/%u  %02u:%02u:%02u.%02u',
  527.             StartTime);
  528.           WriteLn(ReptFile, LineBuff);
  529.           WriteLn(ReptFile);
  530.         END;
  531.     END;
  532.  
  533.     PROCEDURE CreateFileNames;
  534.     VAR C : Char;
  535.     BEGIN
  536.       {-First get LENGTH of Windows directory, then-}
  537.       {-allocate appropiate size for file names.   -}
  538.       WinDirLen := Succ(GetWindowsDirectory(@C, 0));
  539.       GetMem(WinFile, WinDirLen + StrLen(CWinFile));
  540.       GetMem(WinCopy, WinDirLen + StrLen(CWinCopy));
  541.       GetMem(SysFile, WinDirLen + StrLen(CSysFile));
  542.       GetMem(SysCopy, WinDirLen + StrLen(CSysCopy));
  543.       GetWindowsDirectory(WinFile, WinDirLen);
  544.       StrCat(WinFile, '\');
  545.       StrCopy(WinCopy, WinFile);
  546.       StrCopy(SysFile, WinFile);
  547.       StrCopy(SysCopy, WinFile);
  548.       StrCat(WinFile, CWinFile);
  549.       StrCat(WinCopy, CWinCopy);
  550.       StrCat(SysFile, CSysFile);
  551.       StrCat(SysCopy, CSysCopy);
  552.     END;
  553.  
  554.     PROCEDURE CopyFile(OlName, NuName : PChar);
  555.     CONST bufSiz = 32768;
  556.     VAR
  557.       OldF, NewF : File;
  558.       Buffer     : PChar;
  559.       Actual     : Word;
  560.     BEGIN
  561.       GetMem(Buffer, BufSiz);
  562.       Assign(OldF, OlName);
  563.       Assign(NewF, NuName);
  564.       Reset(OldF, 1);
  565.       Rewrite(NewF, 1);
  566.       WHILE NOT EoF(OldF) DO
  567.         BEGIN
  568.           BlockRead(OldF, buffer^, BufSiz, Actual);
  569.           BlockWrite(NewF, buffer^, Actual);
  570.         END;
  571.       Close(NewF);
  572.       Close(OldF);
  573.       FreeMem(Buffer, BufSiz);
  574.     END;
  575.  
  576.     FUNCTION ListExistingFiles : Boolean;
  577.     CONST Root : PChar = 'x:\';
  578.     VAR
  579.       DriveCh   : Char;
  580.       Err       : Byte;
  581.     BEGIN
  582.       WarnWait('Scanning existing files');
  583.       DriveCh := 'A';
  584.       Err := 0;
  585.       WHILE (DriveCh <= 'Z') AND (Err = 0) DO
  586.         BEGIN
  587.           IF Drives[DriveCh] THEN
  588.             BEGIN
  589.                 {-Put the directories for this drive-}
  590.                 {-in the DirList first.             -}
  591.               Root[0] := DriveCh;
  592.               IData.DirList^.Insert(StrNew(Root));
  593.               Mask[0] := DriveCh;
  594.               Err := AllSearcher(Mask, faAnyFile, ListDir);
  595.                 {-Now get the files for this drive.-}
  596.               IF Err = 0 THEN
  597.                 Err := AllSearcher(Mask, faAnyFile, Snap);
  598.             END;
  599.           Inc(DriveCh);
  600.         END;
  601.       EndWait;
  602.       ListExistingFiles := Err = 0;
  603.       IF Err <> 0 THEN MessageBeep(mb_IconStop);
  604.       CASE Err OF
  605.         0   : ; {-Say nothing - all is well.-}
  606.         128 : MessageBox(hWindow, 'INCTRL ran out of memory while '+
  607.                 'trying to list existing files.'^M'Try excluding '+
  608.                 'one or more drives from consideration.', 'ERROR',
  609.                 mb_Ok + mb_IconStop);
  610.         129 : MessageBox(hWindow, 'INCTRL can only remember 16,380 '+
  611.                 'files.'^M'Try excluding one or more drives from '+
  612.                 'consideration.', 'ERROR', mb_Ok + mb_IconStop);
  613.         ELSE
  614.           wvsprintf(LineBuff, 'ERROR # %u, drive X:', Err);
  615.           LineBuff[StrLen(LineBuff)-2] := Pred(DriveCh);
  616.           MessageBox(hWindow, 'INCTRL encountered a DOS error '+
  617.             'while trying to read your disk.'^M'Exit Windows '+
  618.             'and run CHKDSK to identify the problem.', LineBuff,
  619.             mb_Ok + mb_IconStop);
  620.       END;
  621.     END;
  622.  
  623.     FUNCTION ExecuteInstallProgram : Boolean;
  624.     VAR
  625.       InstanceID : THandle;
  626.       InstCmd    : PChar;
  627.       Len        : Word;
  628.     BEGIN
  629.       WarnWait('Executing Install program');
  630.       ExecuteInstallProgram := FALSE;
  631.       Len := pred(StrLen(InstProg));
  632.         {-If it's a BAT file, execute under COMMAND.COM.-}
  633.       IF (InstProg[Len-2] = 'B') AND
  634.          (InstProg[Len-1] = 'A') AND
  635.          (InstProg[Len]   = 'T') THEN
  636.         BEGIN
  637.           Len := Len + StrLen(GetEnvVar('COMSPEC')) + 5;
  638.           GetMem(InstCmd, Len);
  639.           StrCopy(InstCmd, GetEnvVar('COMSPEC'));
  640.           StrCat(InstCmd, ' /C ');
  641.           StrCat(InstCmd, InstProg);
  642.           InstanceID := WinExec(InstCmd, sw_Show);
  643.           FreeMem(InstCmd, Len);
  644.         END
  645.       ELSE InstanceID := WinExec(InstProg, sw_Show);
  646.       EndWait;
  647.       IF InstanceID < 32 THEN Exit;
  648.       REPEAT
  649.         Gasp;
  650.       UNTIL GetModuleUsage(InstanceID) = 0;
  651.       ExecuteInstallProgram := TRUE;
  652.     END;
  653.  
  654.     PROCEDURE RecordNewFiles;
  655.     VAR DriveCh : Char;
  656.     BEGIN
  657.       WriteLn(IData.ReptFile, '*** FILES AND DIRECTORIES ADDED ***');
  658.       WarnWait('Looking for added files');
  659.       FOR DriveCh := 'A' TO 'Z' DO
  660.         IF Drives[DriveCh] THEN
  661.           BEGIN
  662.             Mask[0] := DriveCh;
  663.             AllSearcher(Mask, faAnyFile, UnSnap);
  664.           END;
  665.       EndWait;
  666.       WITH IData DO
  667.         BEGIN
  668.           wvsprintf(LineBuff, 'Install program added %u files and '+
  669.             '%u directories.', NumFiles);
  670.           WriteLn(ReptFile, LineBuff);
  671.           WriteLn(ReptFile);
  672.         END;
  673.     END;
  674.  
  675.     PROCEDURE RecordChangedFiles;
  676.     VAR W : Word;
  677.  
  678.       PROCEDURE WriteOne(Item : PFileRecord); FAR;
  679.       BEGIN
  680.         WITH IData DO
  681.           IF Item^.IsChanged THEN
  682.             BEGIN
  683.               IF ChFiles + ChDirs = 0 THEN
  684.                 WriteLn(ReptFile, '*** FILES AND DIRECTORIES '+
  685.                   'CHANGED ***');
  686.               IF Item^.IsDir THEN
  687.                 BEGIN
  688.                   Inc(ChDirs);
  689.                   Write(ReptFile,'DIR : ');
  690.                 END
  691.               ELSE
  692.                 BEGIN
  693.                   Inc(ChFiles);
  694.                   Write(ReptFile, 'FILE: ');
  695.                 END;
  696.               WriteLn(ReptFile, Item^.GetFullName(LineBuff));
  697.             END;
  698.       END;
  699.  
  700.     BEGIN
  701.       WITH IData DO
  702.         BEGIN
  703.           FileList^.ForEach(@WriteOne);
  704.           IF ChFiles + ChDirs > 0 THEN
  705.             BEGIN
  706.               wvsprintf(LineBuff, 'Install program changed %u '+
  707.                 'files and %u directories.', ChFiles);
  708.               WriteLn(ReptFile, LineBuff);
  709.               WriteLn(ReptFile);
  710.             END;
  711.         END;
  712.     END;
  713.  
  714.     PROCEDURE RecordDeletedFiles;
  715.     VAR W : Word;
  716.  
  717.       PROCEDURE WriteOne(Item : PFileRecord); FAR;
  718.       BEGIN
  719.         WITH IData DO
  720.           IF NOT Item^.IsChanged THEN
  721.           BEGIN
  722.             IF DelDirs + DelFiles = 0 THEN
  723.               WriteLn(ReptFile, '*** FILES AND DIRECTORIES '+
  724.                 'DELETED ***');
  725.             IF Item^.IsDir THEN
  726.               BEGIN
  727.                 Inc(DelDirs);
  728.                 Write(ReptFile,'DIR : ');
  729.               END
  730.             ELSE
  731.               BEGIN
  732.                 Inc(DelFiles);
  733.                 Write(ReptFile, 'FILE: ');
  734.               END;
  735.             WriteLn(ReptFile, Item^.GetFullName(LineBuff));
  736.           END;
  737.       END;
  738.  
  739.     BEGIN
  740.       WITH IData DO
  741.         BEGIN
  742.           FileList^.ForEach(@WriteOne);
  743.           IF DelFiles + DelDirs > 0 THEN
  744.             BEGIN
  745.               wvsprintf(LineBuff, 'Install program deleted %u '+
  746.                 'files and %u directories.', DelFiles);
  747.               WriteLn(ReptFile, LineBuff);
  748.               WriteLn(ReptFile);
  749.             END;
  750.         END;
  751.     END;
  752.  
  753.     FUNCTION CleanHeap : Word;
  754.       {-Delete all sub-allocation blocks that are empty.  Don't-}
  755.       {-delete the block currently pointed-to by HeapList.     -}
  756.       {-Return the number of blocks that could be deleted.     -}
  757.     TYPE
  758.       SubList = ^SubType;
  759.       SubType = RECORD
  760.         Next, Size : Word;
  761.       END;
  762.  
  763.       HList = ^HlType;
  764.       HLType = RECORD
  765.         signature : ARRAY[0..1] OF Char;     {always "TP"}
  766.         reserved  : Word;
  767.         FreeList  : SubType; {start of internal free list}
  768.         SubFree   : Word;  {amount free in suballoc block}
  769.         Next      : Word;             {seg. of next block}
  770.         DataOrg   : Byte;
  771.       END;
  772.     VAR
  773.       H, WasH : HList;
  774.       num     : Word;
  775.     BEGIN
  776.       Num := 0;
  777.       IF HeapList <> 0 THEN
  778.         BEGIN
  779.           WasH := Ptr(HeapList, 0);
  780.           H    := Ptr(WasH^.Next, 0);
  781.           WHILE Seg(H^) <> HeapList DO
  782.             BEGIN
  783.               IF H^.SubFree = HeapBlock - 12 THEN
  784.                 BEGIN
  785.                     {-Cut H out of the chain.-}
  786.                   WasH^.Next := H^.Next;
  787.                     {-Free the memory used by H.-}
  788.                   FreeMem(H, HeapBlock);
  789.                   H := Ptr(WasH^.Next, 0);
  790.                   Inc(Num);
  791.                 END
  792.               ELSE
  793.                 BEGIN
  794.                   WasH := H;
  795.                   H    := Ptr(WasH^.Next, 0);
  796.                 END;
  797.             END;
  798.         END;
  799.       H := Ptr(HeapList, 0);
  800.       IF (H^.Next = HeapList) AND
  801.          (H^.SubFree = HeapBlock-12) THEN
  802.         BEGIN
  803.           FreeMem(H, HeapBlock);
  804.           HeapList := 0;
  805.           Inc(Num);
  806.         END;
  807.       CleanHeap := Num;
  808.     END;
  809.  
  810.     PROCEDURE CompareFiles(NuName, OlName, Nam : PChar);
  811.     {-Compare the Nu file with the Ol' file - the Ol' file-}
  812.     {-is *deleted* at the end of this procedure.          -}
  813.     VAR
  814.       SectBuff   : ARRAY[0..80] OF Char;
  815.       Sects      : PStrICollection;
  816.       OldF, NewF : Text;
  817.       Indx       : Integer;
  818.       NSects,
  819.       NKeyCh,
  820.       NKeys      : Word;
  821.  
  822.       PROCEDURE CheckSections;
  823.       VAR
  824.         SLen : Word;
  825.         Indx : Integer;
  826.       {-Read the old file and store all of its section names in a-}
  827.       {-string collection.  Read the NEW file and report any     -}
  828.       {-sections that didn't exist in the old file.  Hang onto   -}
  829.       {-the section list for use in the next step.               -}
  830.       BEGIN
  831.         WITH IData DO
  832.           BEGIN
  833.             WHILE NOT EoF(OldF) DO
  834.               BEGIN
  835.                 ReadLn(OldF, SectBuff);
  836.                 SLen := StrLen(SectBuff);
  837.                 IF (SectBuff[0] = '[') AND
  838.                    (SectBuff[pred(SLen)] = ']') THEN
  839.                   BEGIN
  840.                     StrLCopy(SectBuff, SectBuff+1, SLen-2);
  841.                     IF Sects^.Search(@SectBuff, Indx) THEN
  842.                       BEGIN
  843.                         StrCopy(LineBuff, 'Duplicate section - ');
  844.                         StrCat(LineBuff, SectBuff);
  845.                         MessageBeep(mb_IconInformation);
  846.                         MessageBox(hWindow, LineBuff, Nam,
  847.                           mb_Ok + mb_IconInformation);
  848.                       END
  849.                     ELSE Sects^.Insert(StrNew(SectBuff));
  850.                   END;
  851.               END;
  852.             WHILE NOT EoF(NewF) DO
  853.               BEGIN
  854.                 ReadLn(NewF, SectBuff);
  855.                 SLen := StrLen(SectBuff);
  856.                 IF (SectBuff[0] = '[') AND
  857.                    (SectBuff[pred(SLen)] = ']') THEN
  858.                   BEGIN
  859.                     StrLCopy(SectBuff, SectBuff+1, SLen-2);
  860.                     IF NOT Sects^.Search(@SectBuff, Indx) THEN
  861.                       BEGIN
  862.                         Sects^.Insert(StrNew(SectBuff));
  863.                         IF NSects = 0 THEN
  864.                           WriteLn(ReptFile, '*** ', Nam,
  865.                             ' SECTIONS ADDED ***');
  866.                         Inc(NSects);
  867.                         WriteLn(ReptFile, SectBuff);
  868.                       END;
  869.                   END;
  870.               END;
  871.             IF NSects > 0 THEN
  872.               BEGIN
  873.                 wvsprintf(LineBuff, '%u sections added to ', NSects);
  874.                 WriteLn(ReptFile, LineBuff, Nam);
  875.                 WriteLn(ReptFile);
  876.               END;
  877.             Inc(NumSects, NSects);
  878.           END;
  879.       END;
  880.  
  881.       PROCEDURE CheckKeys;
  882.       CONST KeyBuffSize = 16384;
  883.       VAR
  884.         KeyBuff  : PChar;
  885.         DevCount,
  886.         Indx     : Integer;
  887.  
  888.         PROCEDURE OneSect(Sect : PChar); FAR;
  889.         {-Iterator routine, executed for each section in the-}
  890.         {-Sects collection.                                 -}
  891.         VAR
  892.           Keys   : PStrICollection;
  893.           V1, V2 : ARRAY[0..512] OF Char;
  894.           P      : PChar;
  895.           Indx   : Integer;
  896.  
  897.           PROCEDURE OneKey(Key : PChar); FAR;
  898.           {-Iterator executed for each key in the current section-}
  899.           BEGIN
  900.             IF (StrIComp(key, 'device') = 0) AND
  901.                (StrIComp(Sect, '386enh') = 0) THEN Exit;
  902.             GetPrivateProfileString(Sect, Key, '', V1, 512, OlName);
  903.             GetPrivateProfileString(Sect, Key, '', V2, 512, NuName);
  904.             IF StrComp(V1, V2) = 0 THEN Exit;
  905.             WITH IData DO
  906.               BEGIN
  907.                 IF NKeyCh = 0 THEN
  908.                   WriteLn(ReptFile, '*** KEYS CHANGED IN ', Nam,
  909.                     ' SECTION [',Sect, '] ***');
  910.                 Inc(NKeyCh);
  911.                 Inc(NumKeyCh);
  912.                 WriteLn(ReptFile, 'BEFORE: ', key, '=', V1);
  913.                 WriteLn(ReptFile, ' AFTER: ', key, '=', V2);
  914.               END;
  915.           END;
  916.  
  917.         BEGIN
  918.           NKeys := 0;
  919.           WITH IData DO
  920.             BEGIN
  921.               New(Keys, Init(8, 8));
  922.               GetPrivateProfileString(Sect, NIL, '', KeyBuff,
  923.                 KeyBuffSize, OlName);
  924.               P := KeyBuff;
  925.               DevCount := 0;
  926.               WHILE P[0] <> #0 DO
  927.                 BEGIN
  928.                   IF (StrIComp(P, 'device') = 0) AND
  929.                      (StrIComp(Sect, '386enh') = 0) THEN
  930.                     BEGIN
  931.                       IF DevCount = 0 THEN Keys^.Insert(StrNew(P));
  932.                       Inc(DevCount);
  933.                     END
  934.                   ELSE
  935.                     BEGIN
  936.                       IF Keys^.Search(P, Indx) THEN
  937.                         BEGIN
  938.                           StrCopy(LineBuff, 'Duplicate key [');
  939.                           StrCat(LineBuff, sect);
  940.                           StrCat(LineBuff, '] ');
  941.                           StrCat(LineBuff, P);
  942.                           MessageBeep(mb_IconInformation);
  943.                           MessageBox(hWindow, LineBuff, Nam,
  944.                             mb_Ok + mb_IconInformation);
  945.                         END
  946.                       ELSE Keys^.Insert(StrNew(P));
  947.                     END;
  948.                   P := StrEnd(P) + 1;
  949.                 END;
  950.               GetPrivateProfileString(Sect, NIL, NIL, KeyBuff,
  951.                 KeyBuffSize, NuName);
  952.               P := KeyBuff;
  953.               WHILE P[0] <> #0 DO
  954.                 BEGIN
  955.                   IF (StrIComp(P, 'device') = 0) AND
  956.                      (StrIComp(Sect, '386enh') = 0) THEN
  957.                     Dec(DevCount);
  958.                   IF NOT Keys^.Search(P, Indx) THEN
  959.                     BEGIN
  960.                       IF NKeys = 0 THEN
  961.                         WriteLn(ReptFile, '*** KEYS ADDED TO ', Nam,
  962.                           ' SECTION [',Sect, '] ***');
  963.                       Inc(NKeys);
  964.                       Inc(NumKeys);
  965.                       GetPrivateProfileString(Sect, P, NIL, V1,
  966.                         512, NuName);
  967.                       WriteLn(ReptFile, P,'=',V1);
  968.                     END;
  969.                   P := StrEnd(P) + 1;
  970.                 END;
  971.               DevCount := -DevCount;
  972.               IF DevCount > 0 THEN
  973.                 BEGIN
  974.                   IF NKeys = 0 THEN
  975.                     WriteLn(ReptFile, '*** KEYS ADDED TO ', Nam,
  976.                       ' SECTION [',Sect, '] ***');
  977.                   Inc(NKeys, DevCount);
  978.                   Inc(NumKeys, DevCount);
  979.                   WriteLn(ReptFile, devCount, ' DEVICE= lines added',
  980.                     ' to the [386Enh] section of SYSTEM.INI');
  981.                 END;
  982.               IF NKeys > 0 THEN
  983.                 BEGIN
  984.                   wvsprintf(LineBuff, '%u keys added to ', NKeys);
  985.                   WriteLn(ReptFile, LineBuff, Nam, ' section [',
  986.                     Sect, ']');
  987.                   WriteLn(ReptFile);
  988.                 END;
  989.               NKeyCh := 0;
  990.               Keys^.ForEach(@OneKey);
  991.               IF NKeyCh > 0 THEN
  992.                 BEGIN
  993.                   wvsprintf(LineBuff, '%u keys changed in ', NKeyCh);
  994.                   WriteLn(ReptFile, LineBuff, Nam, ' section [',
  995.                     Sect, ']');
  996.                   WriteLn(ReptFile);
  997.                 END;
  998.               Dispose(Keys, Done);
  999.             END;
  1000.         END;
  1001.       BEGIN
  1002.         GetMem(KeyBuff, succ(KeyBuffSize));
  1003.         Sects^.ForEach(@OneSect);
  1004.         FreeMem(KeyBuff, succ(KeyBuffSize));
  1005.       END;
  1006.  
  1007.     BEGIN
  1008.       New(Sects, Init(8, 8));
  1009.       Assign(OldF, OlName); Reset(OldF);
  1010.       Assign(NewF, NuName); Reset(NewF);
  1011.       NSects := 0;
  1012.       CheckSections;
  1013.       CheckKeys;
  1014.       Close(NewF);
  1015.       Close(OldF);
  1016.       Erase(OldF);
  1017.       Dispose(Sects, Done);
  1018.     END;
  1019.  
  1020.     PROCEDURE DestroyFileNames;
  1021.     BEGIN
  1022.       FreeMem(WinFile, WinDirLen + StrLen(CWinFile));
  1023.       FreeMem(WinCopy, WinDirLen + StrLen(CWinCopy));
  1024.       FreeMem(SysFile, WinDirLen + StrLen(CSysFile));
  1025.       FreeMem(SysCopy, WinDirLen + StrLen(CSysCopy));
  1026.     END;
  1027.  
  1028.     PROCEDURE DisplayReport;
  1029.     VAR
  1030.       Lines : Word;
  1031.       Line  : String[80];
  1032.       Num   : Word;
  1033.       More  : Boolean;
  1034.     BEGIN
  1035.       WITH IData DO
  1036.         BEGIN
  1037.           Lines := 3;
  1038.           Reset(ReptFile);
  1039.             {-Count the lines in the report.-}
  1040.           WHILE (NOT EoF(ReptFile)) AND (Lines < 818) DO
  1041.             BEGIN
  1042.               ReadLn(ReptFile);
  1043.               Inc(Lines);
  1044.             END;
  1045.           More := NOT EoF(ReptFile);
  1046.           Close(ReptFile);
  1047.           EndWait;
  1048.             {-Set the WinCrt screen to just enough rows.-}
  1049.           ScreenSize.Y := Lines;
  1050.           AutoTracking := FALSE;
  1051.           StrCopy(WindowTitle, 'INCTRL Report - ');
  1052.           StrCat(WindowTitle, ReptName);
  1053.           Num := 0;
  1054.           InitWinCrt;
  1055.           Reset(ReptFile);
  1056.           WHILE (NOT EoF(ReptFile)) AND (Num < Lines) DO
  1057.             BEGIN
  1058.               ReadLn(ReptFile, Line);
  1059.               WriteLn(Line);
  1060.               Inc(Num);
  1061.             END;
  1062.           IF More THEN
  1063.             WriteLn('*** Use NOTEPAD to view entire report ***');
  1064.           Close(ReptFile);
  1065.         END;
  1066.     END;
  1067.  
  1068.   BEGIN
  1069.     FillChar(IData, SizeOf(IData), 0);
  1070.     GlobalData := @IData;
  1071.     WITH IData DO
  1072.       BEGIN
  1073.         New(FileList, Init(32,32));
  1074.         New(DirList, Init(8, 8));
  1075.         CreateFileNames;
  1076.         CopyFile(WinFile, WinCopy);
  1077.         CopyFile(SysFile, SysCopy);
  1078.         Assign(ReptFile, ReptName);
  1079.         ReWrite(ReptFile);
  1080.         WriteHeader;
  1081.         IF NOT ListExistingFiles THEN
  1082.           BEGIN
  1083.             Dispose(DirList, Done);
  1084.             Dispose(FileList, Done);
  1085.             Close(ReptFile);
  1086.             Erase(ReptFile);
  1087.             Exit;
  1088.           END;
  1089.         IF NOT ExecuteInstallProgram THEN
  1090.           BEGIN
  1091.             MessageBeep(mb_IconStop);
  1092.             MessageBox(hWindow, 'Failed to execute install program',
  1093.               InstProg, mb_Ok + mb_IconStop);
  1094.             Dispose(FileList, Done);
  1095.             Close(ReptFile);
  1096.             Erase(ReptFile);
  1097.             Exit;
  1098.           END;
  1099.         RecordNewFiles;
  1100.         RecordChangedFiles;
  1101.         RecordDeletedFiles;
  1102.         Dispose(DirList, Done);
  1103.         Dispose(FileList, Done);
  1104.         WarnWait('Comparing INI files');
  1105.           {-Corresponding EndWait is within DisplayReport-}
  1106.         CompareFiles(WinFile, WinCopy, 'WIN.INI');
  1107.         CompareFiles(SysFile, SysCopy, 'SYSTEM.INI');
  1108.         Close(ReptFile);
  1109.         DestroyFileNames;
  1110.         DisplayReport;
  1111.       END;
  1112.   END;
  1113.  
  1114. {--------------------------------------------------}
  1115. { TMyApplication's method implementations:         }
  1116. {--------------------------------------------------}
  1117.   PROCEDURE TMyApplication.InitMainWindow;
  1118.   BEGIN
  1119.     MainWindow := New(PInCtrlDialog, Init(NIL, AppName));
  1120.   END;
  1121.  
  1122. {--------------------------------------------------}
  1123. { Main program:                                    }
  1124. {--------------------------------------------------}
  1125. VAR MyApp: TMyApplication;
  1126. BEGIN
  1127.   IF GetWinFlags AND wf_pMODE = 0 THEN
  1128.     BEGIN
  1129.       MessageBeep(mb_IconExclamation);
  1130.       MessageBox(0, 'This application requires Standard or Enhanced'+
  1131.         'Mode Windows', 'Application Execution Error',
  1132.         mb_Ok + mb_IconExclamation);
  1133.       Halt;
  1134.     END;
  1135.   MyApp.Init(AppName);
  1136.   MyApp.Run;
  1137.   MyApp.Done;
  1138. END.
  1139.